#include <glf.h>
#include <glfu.h>
#include <glfwindow.h>	//for glfGetWidth()
#include <memory.h>
#include <stdlib.h>

//to draw with GL_LINES
static void generateCubeWireframe( float *p, unsigned char *i )
{
	static const float	positions[8*3]={
		0.5f,-0.5f,0.5f,	//0
		-0.5f,-0.5f,0.5f,	//1
		-0.5f,0.5f,0.5f,	//2
		0.5f,0.5f,0.5f,		//3
		0.5f,-0.5f,-0.5f,	//4
		-0.5f,-0.5f,-0.5f,	//5
		-0.5f,0.5f,-0.5f,	//6
		0.5f,0.5f,-0.5f		//7
	};
	static const unsigned char	indices[24]={
		0,
		1,
		2,
		3,
		4,
		5,
		6,
		7,
		1,	
		2,
		0,
		3,
		5,
		6,
		4,
		7,
		1,
		5,
		2,
		6,
		0,
		4,
		3,
		7
	};
	memcpy( p, positions, sizeof( positions ) );
	memcpy( i, indices, sizeof( indices ) );
}




//can draw with GL_POINTS for point rendering
//can draw with GL_LINE_LOOP for "outline"
//can draw with GL_TRIANGLE_FAN for filled

static void generateSquare( float *p )
{
	static const float	positions[8]={
		0.5f,-0.5f,
		-0.5f,-0.5f,
		-0.5f,0.5f,
		0.5f,0.5f
	};
	memcpy( p, positions, sizeof( positions ) );
}

//can draw with GL_POINTS or GL_LINE_LOOP
static void generateCircleWireframe( float *p, const size_t count )
{
	const float a = M_PI * 2.0f / (float)count;
	float b = 0.0f;
	size_t i,j=0;
	float x,y;
	if( count )
	{
		for(i=0;i<count;i++)
		{
			x = cosf( b ) * 0.5f;
			y = sinf( b ) * 0.5f;
			p[j++]=x;
			p[j++]=y;
			b += a;
		}
	}
}

//can draw with GL_POINTS for point rendering
//can draw with GL_TRIANGLE_FAN for filled

static void generateCircle( float *p, const size_t count )
{
	const float a = M_PI * 2.0f / (float)(count-2);	// divide by zero if count is 2...need to prevent this
	float b = 0.0f;
	size_t i,j=0;
	float x,y;
	if( count > 2 )
	{
		p[j++]=0;
		p[j++]=0;
		for(i=0;i<count-2;i++)
		{
			b = i * a;
			x = cosf( b ) * 0.5f;
			y = sinf( b ) * 0.5f;
			p[j++]=x;
			p[j++]=y;
		}
		p[j++]=0.5f;
		p[j++]=0;
	}
}

int glfuGenerateShape( glfuShape_t *shape, int type, int wireframe )
{
	memset( shape, 0, sizeof( glfuShape_t ) );
	switch( type )
	{
	case GLFU_SQUARE:
		shape->vertexTypeSize = 2;
		shape->vertexType = GL_FLOAT;
		if( wireframe )
			shape->primitiveType = GL_LINE_LOOP;
		else
			shape->primitiveType = GL_TRIANGLE_FAN;
		shape->numVertices = 4;
		shape->vertices = malloc( 4 * 2 * sizeof( float ) );
		generateSquare( shape->vertices );
		return 0;
	case GLFU_CIRCLE:
		shape->vertexTypeSize = 2;
		shape->vertexType = GL_FLOAT;
		if( wireframe )
		{
			shape->primitiveType = GL_LINE_LOOP;
		}
		else
		{
			shape->primitiveType = GL_TRIANGLE_FAN;
		}
		shape->numVertices = glfGetWidth()/10;
		shape->vertices = malloc( shape->numVertices * 2 * sizeof( float ) );
		if( wireframe )
			generateCircleWireframe( shape->vertices, shape->numVertices );
		else
			generateCircle( shape->vertices, shape->numVertices );
		return 0;
	case GLFU_CUBE:
		if( wireframe )
		{

			shape->primitiveType = GL_LINES;

			shape->vertexTypeSize = 3;
			shape->vertexType = GL_FLOAT;
			shape->numVertices = 8;
			shape->vertices = malloc( 8 * 3 * sizeof( float ) );

			shape->indexType = GL_UNSIGNED_BYTE;
			shape->numIndices = 24;
			shape->indices = malloc( 24 * sizeof( unsigned char ) );

			generateCubeWireframe( shape->vertices, shape->indices );

			return 0;
		}
		break;
	default:
		break;
	}
	return -1;
}

void glfuDeleteShape( glfuShape_t *shape )
{
	if( shape->vertices )
	{
		free( shape->vertices );
		shape->vertices = 0;
	}
	if( shape->normals )
	{
		free( shape->normals );
		shape->normals = 0;
	}
	if( shape->indices )
	{
		free( shape->indices );
		shape->indices = 0;
	}
}